import json
from PyQt5.QtWidgets import (QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, 
                             QLabel, QLineEdit, QPushButton, QComboBox, 
                             QFileDialog, QMessageBox, QSystemTrayIcon, QMenu, 
                             QTabWidget, QListWidget, QTextEdit, QProgressBar,
                             QGroupBox, QCheckBox, QInputDialog, QTableWidget, QTableWidgetItem, QHeaderView,
                             QStyledItemDelegate, QGridLayout)
from PyQt5.QtCore import QSize
from PyQt5.QtGui import (QIntValidator, QIcon, QTextDocument, QTextOption, 
                        QColor, QFont, QLinearGradient, QPen)
from PyQt5.QtCore import Qt, QTimer, QSize, QRect
from PyQt5.QtCore import Qt, QTimer, QSize
from PyQt5.QtWidgets import QStyle
from datetime import datetime

class BrowseButtonDelegate(QStyledItemDelegate):
    def __init__(self, parent=None, file_filter=""):
        super().__init__(parent)
        self.parent = parent
        self.file_filter = file_filter

    def createEditor(self, parent, option, index):
        return None  # 禁用编辑

    def paint(self, painter, option, index):
        # 获取表格的当前鼠标位置和悬停的单元格
        table = self.parent
        viewport = table.viewport()
        mouse_pos = viewport.mapFromGlobal(table.cursor().pos())
        current_index = table.indexAt(mouse_pos)
        
        # 获取文本内容
        text = index.data(Qt.DisplayRole)
        
        painter.save()
        
        # 绘制背景
        if option.state & QStyle.State_Selected:
            # 即使文本为空，也绘制选中背景
            painter.fillRect(option.rect, option.palette.highlight())
            painter.setPen(option.palette.highlightedText().color())
        else:
            painter.setPen(Qt.black)
        
        # 如果有文本，则绘制文本
        if text:
            text_rect = option.rect.adjusted(4, 2, -4, -2)
            painter.drawText(text_rect, Qt.TextWordWrap | Qt.AlignLeft | Qt.AlignVCenter, text)
        
        painter.restore()
        
        # 只在鼠标悬停时绘制浏览按钮
        if current_index == index and viewport.rect().contains(mouse_pos):
            painter.save()
            
            # 绘制完全不透明的背景
            painter.fillRect(option.rect, QColor(240, 240, 240))
            
            # 绘制边框
            painter.setPen(QPen(QColor(180, 180, 180), 1))
            painter.drawRect(option.rect)
            
            # 绘制浏览文本
            painter.setPen(QColor(40, 40, 40))
            painter.drawText(option.rect, Qt.AlignCenter, "浏览")
            
            painter.restore()
            # 使用整个单元格区域作为按钮
            button_rect = option.rect
            
            # 绘制按钮背景
            painter.save()
            painter.setRenderHint(painter.Antialiasing)  # 启用抗锯齿
            
            # 创建渐变背景
            gradient = QLinearGradient(button_rect.topLeft(), button_rect.bottomLeft())
            gradient.setColorAt(0, QColor(250, 250, 250))  # 顶部颜色，更亮
            gradient.setColorAt(0.5, QColor(240, 240, 240))  # 中间颜色
            gradient.setColorAt(1, QColor(230, 230, 230))  # 底部颜色
            
            # 绘制主体背景
            painter.setPen(Qt.NoPen)
            painter.setBrush(gradient)
            painter.drawRect(button_rect)
            
            # 绘制边框效果
            border_color = QColor(180, 180, 180)  # 边框颜色
            painter.setPen(QPen(border_color, 1))
            painter.drawRect(button_rect)
            
            # 绘制顶部高光效果
            highlight_rect = QRect(button_rect)
            highlight_rect.setHeight(button_rect.height() // 3)  # 高光区域调整为1/3高度
            highlight_gradient = QLinearGradient(highlight_rect.topLeft(), highlight_rect.bottomLeft())
            highlight_gradient.setColorAt(0, QColor(255, 255, 255))  # 纯白色
            highlight_gradient.setColorAt(1, QColor(250, 250, 250))  # 接近白色
            painter.setBrush(highlight_gradient)
            painter.setPen(Qt.NoPen)
            painter.drawRect(highlight_rect)
            
            # 绘制底部阴影效果
            shadow_rect = QRect(button_rect)
            shadow_rect.setTop(button_rect.bottom() - button_rect.height() // 4)  # 底部1/4区域
            shadow_gradient = QLinearGradient(shadow_rect.topLeft(), shadow_rect.bottomLeft())
            shadow_gradient.setColorAt(0, QColor(230, 230, 230))  # 与底色相同
            shadow_gradient.setColorAt(1, QColor(220, 220, 220))  # 稍暗
            painter.setBrush(shadow_gradient)
            painter.setPen(Qt.NoPen)
            painter.drawRect(shadow_rect)
            
            # 绘制完全不透明的背景
            painter.fillRect(button_rect, QColor(240, 240, 240))  # 使用纯色背景
            
            # 绘制边框
            painter.setPen(QPen(QColor(180, 180, 180), 1))
            painter.drawRect(button_rect)
            
            # 绘制浏览文本（带阴影效果）
            font = painter.font()
            font.setBold(True)
            painter.setFont(font)
            
            # 绘制文本阴影
            shadow_offset = 1
            painter.setPen(QColor(150, 150, 150))  # 阴影颜色
            shadow_rect = button_rect.adjusted(shadow_offset, shadow_offset, shadow_offset, shadow_offset)
            painter.drawText(shadow_rect, Qt.AlignCenter, "浏览")
            
            # 绘制主文本
            painter.setPen(QColor(40, 40, 40))  # 深灰色文本
            painter.drawText(button_rect, Qt.AlignCenter, "浏览")
            
            painter.restore()

    def editorEvent(self, event, model, option, index):
        if event.type() == event.MouseMove:
            # 检查鼠标是否在当前单元格内
            if option.rect.contains(event.pos()):
                # 强制重绘当前单元格
                self.parent.viewport().update(option.rect)
            return True
            
        elif event.type() == event.MouseButtonRelease:
            if option.rect.contains(event.pos()):
                # 打开文件选择对话框
                file_path, _ = QFileDialog.getOpenFileName(
                    self.parent,
                    "选择文件",
                    "",
                    self.file_filter
                )
                if file_path:
                    model.setData(index, file_path, Qt.EditRole)
                return True
            
        return False

class ConfigPathDelegate(BrowseButtonDelegate):
    def __init__(self, parent=None):
        super().__init__(parent, "配置文件 (*.ini *.yaml *.yml *.json *.properties)")

class ServicePathDelegate(BrowseButtonDelegate):
    def __init__(self, parent=None):
        super().__init__(parent, "可执行文件 (*.exe *.bat);;所有文件 (*)")

class TextEditDelegate(QStyledItemDelegate):
    def createEditor(self, parent, option, index):
        editor = QTextEdit(parent)
        editor.setWordWrapMode(QTextOption.WrapAtWordBoundaryOrAnywhere)
        editor.setLineWrapMode(QTextEdit.WidgetWidth)
        editor.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        editor.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        return editor

    def setEditorData(self, editor, index):
        value = index.model().data(index, Qt.DisplayRole)
        editor.setPlainText(value)
        editor.selectAll()

    def setModelData(self, editor, model, index):
        value = editor.toPlainText()
        model.setData(index, value, Qt.EditRole)

    def updateEditorGeometry(self, editor, option, index):
        editor.setGeometry(option.rect)

    def paint(self, painter, option, index):
        # 保存当前的文本对齐方式
        text_option = QTextOption()
        text_option.setWrapMode(QTextOption.WrapAtWordBoundaryOrAnywhere)
        
        # 获取文本内容
        text = index.data(Qt.DisplayRole)
        if not text:
            return
            
        # 准备绘制
        painter.save()
        
        # 如果单元格被选中，只绘制背景色，不改变文本样式
        if option.state & QStyle.State_Selected:
            painter.fillRect(option.rect, option.palette.highlight())
            
        # 设置固定的文本颜色，不受选中状态影响
        painter.setPen(Qt.black)
        
        # 计算文本区域，考虑内边距
        text_rect = option.rect.adjusted(4, 2, -4, -2)  # 4像素的左右边距，2像素的上下边距
        
        # 使用固定的字体设置
        font = painter.font()
        font.setBold(False)  # 确保文本不会加粗
        painter.setFont(font)
        
        # 绘制文本
        painter.drawText(text_rect, Qt.TextWordWrap | Qt.AlignLeft | Qt.AlignVCenter, text)
        
        painter.restore()

    def sizeHint(self, option, index):
        # 获取文本内容
        text = index.data(Qt.DisplayRole)
        if not text:
            return super().sizeHint(option, index)
            
        # 创建一个文档来计算文本高度
        doc = QTextDocument()
        doc.setDefaultFont(option.font)
        doc.setTextWidth(option.rect.width() - 8)  # 考虑左右边距
        doc.setPlainText(text)
        
        # 返回合适的大小
        return QSize(option.rect.width(), int(doc.size().height()) + 4)  # 4像素的上下边距


class UserInterface(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("SQL服务器数据库密码修改工具")
        self.setGeometry(100, 100, 800, 600)
        
        self.initUI()
        
        # 初始化时加载配置
        self.load_config()
        
    def load_config(self):
        """加载配置文件"""
        try:
            with open("config/config.json", "r", encoding='utf-8') as f:
                config = json.load(f)
                
                # 确保UI组件已初始化
                if not hasattr(self, 'freq_min'):
                    self.initUI()
                
                # 初始化频率设置
                if "frequency" in config:
                    self.freq_min.setText(str(config["frequency"]["min"]))
                    self.freq_max.setText(str(config["frequency"]["max"]))
                
                # 初始化复杂度设置
                if "complexity" in config:
                    self.length_check.setChecked(config["complexity"]["length"])
                    self.upper_check.setChecked(config["complexity"]["upper"])
                    self.lower_check.setChecked(config["complexity"]["lower"])
                    self.number_check.setChecked(config["complexity"]["number"])
                    self.special_check.setChecked(config["complexity"]["special"])
                
                # 初始化服务列表
                if "services" in config:
                    self.service_table.setRowCount(0)  # 清空现有行                    self.service_table.setColumnCount(5)
                    self.service_table.setHorizontalHeaderLabels(["选择", "服务名称", "服务路径", "配置文件路径", "操作"])
                    self.service_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
                    for service in config["services"]:
                        row = self.service_table.rowCount()
                        self.service_table.insertRow(row)
                        
                        # 设置第一列为复选框
                        checkbox = QCheckBox()
                        checkbox.setChecked(False)
                        checkbox_widget = QWidget()
                        checkbox_layout = QHBoxLayout(checkbox_widget)
                        checkbox_layout.addWidget(checkbox)
                        checkbox_layout.setAlignment(Qt.AlignCenter)
                        checkbox_layout.setContentsMargins(0, 0, 0, 0)
                        checkbox_widget.setLayout(checkbox_layout)
                        self.service_table.setCellWidget(row, 0, checkbox_widget)
                        
                        # 设置其他列
                        # 设置多行显示
                        name_item = QTableWidgetItem(service["name"])
                        name_item.setFlags(name_item.flags() | Qt.TextWordWrap)
                        path_item = QTableWidgetItem(service["path"])
                        path_item.setFlags(path_item.flags() | Qt.TextWordWrap)
                        config_path_item = QTableWidgetItem(service["config_path"])
                        config_path_item.setFlags(config_path_item.flags() | Qt.TextWordWrap)
                        
                        self.service_table.setItem(row, 1, name_item)
                        self.service_table.setItem(row, 2, path_item)
                        self.service_table.setItem(row, 3, config_path_item)
                        self.service_table.resizeRowsToContents()
                        
                        # 连接编辑框失去焦点信号
                        self.service_table.cellChanged.connect(self.on_service_name_changed)
                        self.service_table.cellDoubleClicked.connect(lambda row, column: self.service_table.edit(self.service_table.currentIndex()))
                        self.service_table.itemDelegate().closeEditor.connect(lambda editor, hint: self.on_service_name_edit_lost_focus(self.service_table.currentRow(), self.service_table.currentColumn()))
                        
                        # 添加删除按钮
                        btn = QPushButton("删除")
                        btn.clicked.connect(lambda: self.del_service())
                        btn_widget = QWidget()
                        btn_layout = QHBoxLayout(btn_widget)
                        btn_layout.addWidget(btn)
                        btn_layout.setAlignment(Qt.AlignCenter)
                        btn_layout.setContentsMargins(0, 0, 0, 0)
                        btn_widget.setLayout(btn_layout)
                        self.service_table.setCellWidget(row, 4, btn_widget)
                
                self.append_log("配置加载", True, "配置文件加载成功")
                self.update()  # 强制更新UI
        except FileNotFoundError:
            self.append_log("配置加载", False, "配置文件不存在，将使用默认配置")
        except Exception as e:
            self.append_log("配置加载", False, f"加载配置文件失败: {str(e)}")
        
        # 系统托盘设置
        self.tray_icon = QSystemTrayIcon(self)
        self.tray_icon.setIcon(QIcon(":/icons/app_icon.png"))
        self.tray_menu = QMenu()
        self.tray_menu.addAction("打开主界面", self.show)
        self.tray_menu.addAction("暂停任务", self.toggle_pause)
        self.tray_menu.addSeparator()
        self.tray_menu.addAction("退出", self.close)
        self.tray_icon.setContextMenu(self.tray_menu)
        self.tray_icon.show()
        
        # 状态定时器
        self.status_timer = QTimer()
        self.status_timer.timeout.connect(self.update_tray_status)
        self.status_timer.start(5000)
        
        self.is_paused = False
        
    def toggle_pause(self):
        """切换暂停状态"""
        self.is_paused = not self.is_paused
        if self.is_paused:
            self.status_timer.stop()
            self.statusBar().showMessage("任务已暂停")
        else:
            self.status_timer.start(5000)
            self.statusBar().showMessage("任务已恢复")
        self.update_tray_status()
        
    def update_tray_status(self):
        """更新系统托盘状态"""
        if self.is_paused:
            self.tray_icon.setToolTip("SQL密码修改工具 - 已暂停")
        else:
            self.tray_icon.setToolTip("SQL密码修改工具 - 运行中")
    
    def initUI(self):
        # 主窗口部件
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        
        # 主布局
        main_layout = QVBoxLayout()
        central_widget.setLayout(main_layout)
        
        # 创建Tab控件
        self.tabs = QTabWidget()
        
        # 数据库连接设置区域
        self.db_group = QGroupBox("数据库连接设置")
        db_layout = QVBoxLayout()
        
        # IP地址输入
        ip_layout = QHBoxLayout()
        ip_layout.addWidget(QLabel("IP地址:"))
        self.db_ip = QLineEdit()
        ip_layout.addWidget(self.db_ip)
        db_layout.addLayout(ip_layout)
        
        # 端口输入
        port_layout = QHBoxLayout()
        port_layout.addWidget(QLabel("端口:"))
        self.db_port = QLineEdit()
        self.db_port.setValidator(QIntValidator(1, 65535))
        port_layout.addWidget(self.db_port)
        db_layout.addLayout(port_layout)
        
        # 用户名输入
        user_layout = QHBoxLayout()
        user_layout.addWidget(QLabel("用户名:"))
        self.db_user = QLineEdit()
        user_layout.addWidget(self.db_user)
        db_layout.addLayout(user_layout)
        
        # 密码输入
        pwd_layout = QHBoxLayout()
        pwd_layout.addWidget(QLabel("初始密码:"))
        self.db_pwd = QLineEdit()
        self.db_pwd.setEchoMode(QLineEdit.Password)
        pwd_layout.addWidget(self.db_pwd)
        db_layout.addLayout(pwd_layout)
        
        self.db_group.setLayout(db_layout)
        
        # 密码修改配置Tab
        self.config_tab = QWidget()
        self.tabs.addTab(self.config_tab, "密码修改配置")
        
        # 服务管理Tab
        self.service_tab = QWidget()
        self.tabs.addTab(self.service_tab, "服务管理")
        
        # 操作日志Tab
        self.log_tab = QWidget()
        self.tabs.addTab(self.log_tab, "操作日志")
        
        # 添加Tab控件到主布局
        main_layout.addWidget(self.tabs)
        
        # 状态栏
        self.statusBar().showMessage("准备就绪")
        
        # 初始化所有UI组件
        self.freq_min = QLineEdit()
        self.freq_max = QLineEdit()
        self.length_check = QCheckBox()
        self.upper_check = QCheckBox()
        self.lower_check = QCheckBox()
        self.number_check = QCheckBox()
        self.special_check = QCheckBox()
        self.service_table = QTableWidget()
        
        # 初始化各个Tab的内容
        self.initConfigTab()
        self.initServiceTab()
        self.initLogTab()
        
    def initConfigTab(self):
        """初始化密码修改配置Tab"""
        layout = QVBoxLayout()
        self.config_tab.setLayout(layout)
        
        # 数据库连接设置
        db_group = QGroupBox("数据库连接设置")
        db_layout = QVBoxLayout()
        
        # 创建表单布局
        form_layout = QGridLayout()
        
        # IP地址输入
        ip_label = QLabel("IP地址:")
        ip_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
        self.db_ip = QLineEdit()
        self.db_ip.setFixedWidth(200)  # 设置固定宽度
        form_layout.addWidget(ip_label, 0, 0)
        form_layout.addWidget(self.db_ip, 0, 1)
        
        # 端口输入
        port_label = QLabel("端口:")
        port_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
        self.db_port = QLineEdit()
        self.db_port.setValidator(QIntValidator(1, 65535))
        self.db_port.setFixedWidth(100)  # 设置固定宽度
        form_layout.addWidget(port_label, 1, 0)
        form_layout.addWidget(self.db_port, 1, 1)
        
        # 用户名输入
        user_label = QLabel("用户名:")
        user_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
        self.db_user = QLineEdit()
        self.db_user.setFixedWidth(200)  # 设置固定宽度
        form_layout.addWidget(user_label, 2, 0)
        form_layout.addWidget(self.db_user, 2, 1)
        
        # 密码输入
        pwd_label = QLabel("密码:")
        pwd_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
        self.db_pwd = QLineEdit()
        self.db_pwd.setEchoMode(QLineEdit.Password)
        self.db_pwd.setFixedWidth(200)  # 设置固定宽度
        form_layout.addWidget(pwd_label, 3, 0)
        form_layout.addWidget(self.db_pwd, 3, 1)
        
        # 数据库名称输入
        db_name_label = QLabel("数据库名称:")
        db_name_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
        self.db_name = QLineEdit()
        self.db_name.setFixedWidth(200)
        form_layout.addWidget(db_name_label, 4, 0)
        form_layout.addWidget(self.db_name, 4, 1)
        
        # 设置列拉伸因子
        form_layout.setColumnMinimumWidth(0, 80)  # 设置标签列的最小宽度
        form_layout.setColumnStretch(1, 0)  # 输入框列不拉伸
        form_layout.setColumnStretch(2, 1)  # 添加第三列并设置拉伸因子，使输入框右侧有空白
        
        db_layout.addLayout(form_layout)
        
        db_group.setLayout(db_layout)
        layout.addWidget(db_group)
        
        # 密码修改频率设置
        freq_group = QGroupBox("密码修改频率")
        freq_layout = QHBoxLayout()
        
        freq_label = QLabel("修改频率(天):")
        freq_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
        freq_layout.addWidget(freq_label)
        
        self.freq_min = QLineEdit("70")
        self.freq_min.setValidator(QIntValidator(1, 365))
        self.freq_min.setFixedWidth(60)  # 设置固定宽度
        freq_layout.addWidget(self.freq_min)
        
        freq_layout.addWidget(QLabel("-"))
        
        self.freq_max = QLineEdit("90")
        self.freq_max.setValidator(QIntValidator(1, 365))
        self.freq_max.setFixedWidth(60)  # 设置固定宽度
        freq_layout.addWidget(self.freq_max)

        # 添加测试按钮
        self.test_btn = QPushButton("测试")
        self.test_btn.setToolTip("手动触发密码修改流程")
        self.test_btn.clicked.connect(self.trigger_password_change)
        freq_layout.addWidget(self.test_btn)
        
        freq_layout.addStretch()  # 添加弹性空间，使控件靠左对齐
        freq_group.setLayout(freq_layout)
        layout.addWidget(freq_group)
        
        # 密码复杂度设置
        complexity_group = QGroupBox("密码复杂度")
        complexity_layout = QHBoxLayout()
        complexity_layout.addWidget(QLabel("密码复杂度要求:"))
        self.length_check = QCheckBox("长度≥8")
        self.upper_check = QCheckBox("包含大写")
        self.lower_check = QCheckBox("包含小写")
        self.number_check = QCheckBox("包含数字")
        self.special_check = QCheckBox("包含特殊字符")
        complexity_layout.addWidget(self.length_check)
        complexity_layout.addWidget(self.upper_check)
        complexity_layout.addWidget(self.lower_check)
        complexity_layout.addWidget(self.number_check)
        complexity_layout.addWidget(self.special_check)
        complexity_group.setLayout(complexity_layout)
        layout.addWidget(complexity_group)
        
        # 从配置文件加载值
        try:
            with open("config/config.json", "r", encoding='utf-8') as f:
                config = json.load(f)
                # 加载数据库设置
                if "database" in config:
                    self.db_ip.setText(config["database"].get("ip", ""))
                    self.db_port.setText(str(config["database"].get("port", "")))
                    self.db_user.setText(config["database"].get("username", ""))
                    self.db_pwd.setText(config["database"].get("password", ""))
                    self.db_name.setText(config["database"].get("database", ""))
                
                # 加载频率设置
                if "frequency" in config:
                    self.freq_min.setText(str(config["frequency"].get("min", "70")))
                    self.freq_max.setText(str(config["frequency"].get("max", "90")))
                
                # 加载复杂度设置
                if "complexity" in config:
                    self.length_check.setChecked(config["complexity"].get("length", True))
                    self.upper_check.setChecked(config["complexity"].get("upper", True))
                    self.lower_check.setChecked(config["complexity"].get("lower", True))
                    self.number_check.setChecked(config["complexity"].get("number", True))
                    self.special_check.setChecked(config["complexity"].get("special", True))
        except Exception as e:
            self.append_log("配置加载", False, f"加载配置文件失败: {str(e)}")
        
        # 保存按钮
        save_btn = QPushButton("保存设置")
        save_btn.clicked.connect(self.save_config)
        layout.addWidget(save_btn)
        
    def initServiceTab(self):
        """初始化服务管理Tab"""
        layout = QVBoxLayout()
        self.service_tab.setLayout(layout)
        
        # 服务表格
        self.service_table = QTableWidget()
        self.service_table.setColumnCount(5)
        self.service_table.setHorizontalHeaderLabels(['选择', '服务名称', '服务路径', '配置文件路径', '配置内容'])
        
        # 从配置文件加载服务数据
        try:
            with open("config/config.json", "r", encoding='utf-8') as f:
                config = json.load(f)
                services = config.get("services", [])
                
                # 设置第一列为复选框
                for row in range(self.service_table.rowCount()):
                    checkbox = QCheckBox()
                    checkbox.setChecked(False)
                    checkbox_widget = QWidget()
                    checkbox_layout = QHBoxLayout(checkbox_widget)
                    checkbox_layout.addWidget(checkbox)
                    checkbox_layout.setAlignment(Qt.AlignCenter)
                    checkbox_layout.setContentsMargins(0, 0, 0, 0)
                    checkbox_widget.setLayout(checkbox_layout)
                    self.service_table.setCellWidget(row, 0, checkbox_widget)
                    
                    # 设置服务名称和服务路径
                    if row < len(services):
                        service = services[row]
                        self.service_table.setItem(row, 1, QTableWidgetItem(service["name"]))
                        self.service_table.setItem(row, 2, QTableWidgetItem(service["path"]))
                
                # 设置表格属性
                self.service_table.setEditTriggers(QTableWidget.DoubleClicked)
                self.service_table.setSelectionMode(QTableWidget.ExtendedSelection)
                self.service_table.setSelectionBehavior(QTableWidget.SelectRows)
                self.service_table.setWordWrap(True)
                self.service_table.setTextElideMode(Qt.ElideNone)
                
                # 设置表头样式
                header = self.service_table.horizontalHeader()
                header.setStretchLastSection(True)
                header.setSectionResizeMode(0, QHeaderView.Fixed)
                header.setSectionResizeMode(1, QHeaderView.Stretch)
                header.setSectionResizeMode(2, QHeaderView.Stretch)
                header.setSectionResizeMode(3, QHeaderView.Stretch)
                self.service_table.setColumnWidth(0, 20)  # 固定选择列宽度为仅显示复选框
                
                # 连接点击信号
                self.service_table.cellClicked.connect(self.on_table_cell_clicked)
                
                # 设置表头字体
                font = header.font()
                font.setBold(True)
                header.setFont(font)
                
                # 设置表头不响应鼠标事件
                header.setHighlightSections(False)
                
                # 禁用项目文本格式化
                self.service_table.setStyleSheet("QTableWidget::item { border: none; }")
                
                # 设置单元格文本自动换行和行高自适应
                self.service_table.setWordWrap(True)
                vertical_header = self.service_table.verticalHeader()
                vertical_header.setSectionResizeMode(QHeaderView.ResizeToContents)
                vertical_header.setDefaultSectionSize(40)  # 设置默认行高
                vertical_header.setMinimumSectionSize(30)  # 设置最小行高
                
                # 连接单元格内容变化信号
                self.service_table.itemChanged.connect(self.on_cell_changed)
                
                # 设置单元格编辑属性
                text_delegate = TextEditDelegate(self.service_table)
                service_path_delegate = ServicePathDelegate(self.service_table)
                config_path_delegate = ConfigPathDelegate(self.service_table)
                
                # 为不同列设置不同的代理
                self.service_table.setItemDelegateForColumn(1, text_delegate)  # 服务名称列
                self.service_table.setItemDelegateForColumn(2, service_path_delegate)  # 服务路径列
                self.service_table.setItemDelegateForColumn(3, config_path_delegate)  # 配置文件路径列
                
                layout.addWidget(self.service_table)
                
                # 启用鼠标追踪以支持悬停效果
                self.service_table.setMouseTracking(True)
                self.service_table.viewport().setMouseTracking(True)
                
                # 安装事件过滤器来处理鼠标离开事件
                self.service_table.viewport().installEventFilter(self)
                
                # 确保视图能接收鼠标离开事件
                self.service_table.viewport().setAttribute(Qt.WA_Hover)
                
                # 确保表格至少有一行
                if self.service_table.rowCount() == 0:
                    self.service_table.insertRow(0)
                    
        except Exception as e:
            self.append_log("UI初始化", False, f"表格控件初始化失败: {str(e)}")
            self.service_table.resizeRowsToContents()
        
        # 操作按钮
        btn_layout = QHBoxLayout()
        self.add_btn = QPushButton("添加服务")
        self.del_btn = QPushButton("删除服务")
        self.restart_btn = QPushButton("重启选中")
        self.select_all_btn = QPushButton("全选")
        self.browse_btn = QPushButton("浏览配置...")
        
        btn_layout.addWidget(self.add_btn)
        btn_layout.addWidget(self.del_btn)
        btn_layout.addWidget(self.restart_btn)
        btn_layout.addWidget(self.select_all_btn)
        btn_layout.addWidget(self.browse_btn)
        layout.addLayout(btn_layout)
        

        
        # 连接信号
        self.add_btn.clicked.connect(self.add_service)
        self.del_btn.clicked.connect(self.del_service)
        self.restart_btn.clicked.connect(self.restart_services)
        self.select_all_btn.clicked.connect(self.select_all_services)
        self.browse_btn.clicked.connect(self.browse_config)
        
    def browse_config(self):
        """配置文件选择"""
        selected_rows = []
        for row in range(self.service_table.rowCount()):
            checkbox_widget = self.service_table.cellWidget(row, 0)
            checkbox = checkbox_widget.findChild(QCheckBox)
            if checkbox and checkbox.isChecked():
                selected_rows.append(row)
                
        if not selected_rows:
            QMessageBox.warning(self, "警告", "请先勾选要配置的服务前的复选框！")
            return
            
        file_path, _ = QFileDialog.getOpenFileName(self, "选择配置文件", "", "配置文件 (*.ini *.yaml *.yml *.json *.properties)")
        if file_path:
            for row in selected_rows:
                # 只更新配置文件路径列(第3列)，不修改服务路径列(第2列)
                self.service_table.setItem(row, 3, QTableWidgetItem(file_path))
                
                # 添加对表格项是否为空的检查
                service_item = self.service_table.item(row, 1)
                service_name = service_item.text() if service_item else "未命名服务"
                self.append_log("配置管理", True, f"已为服务 {service_name} 更新配置文件路径")
            self.save_config()
        
    def select_all_services(self):
        """全选服务列表中的所有服务"""
        self.service_table.selectAll()
        for row in range(self.service_table.rowCount()):
            checkbox_widget = self.service_table.cellWidget(row, 0)
            checkbox = checkbox_widget.findChild(QCheckBox)
            checkbox.setChecked(True)
        
    def restart_services(self):
        """重启选中的服务"""
        selected_rows = [index.row() for index in self.service_table.selectedIndexes()]
        if not selected_rows:
            QMessageBox.warning(self, "警告", "请先选择要重启的服务！")
            return
            
        for row in selected_rows:
            service_name = self.service_table.item(row, 0).text()
            # 这里可以添加实际重启服务的逻辑
            self.append_log("服务重启", True, f"已重启服务: {service_name}")
        
    def add_service(self):
        """添加新服务到服务列表"""
        # 直接选择服务程序路径
        file_path, _ = QFileDialog.getOpenFileName(self, "选择服务程序", "", "可执行文件 (*.exe *.bat);;所有文件 (*)")
        if not file_path:
            return
            
        # 从文件路径中提取服务名称（使用bat或exe文件的上层目录名）
        import os
        file_name = os.path.basename(file_path)
        if file_name.lower().endswith(('.bat', '.exe')):
            # 获取文件所在目录的路径
            dir_path = os.path.dirname(file_path)
            # 获取该目录的名称
            service_name = os.path.basename(dir_path)
        else:
            service_name = file_name
        
        row = self.service_table.rowCount()
        self.service_table.insertRow(row)
        
        # 设置第一列为复选框
        checkbox = QCheckBox()
        checkbox.setChecked(False)
        checkbox_widget = QWidget()
        checkbox_layout = QHBoxLayout(checkbox_widget)
        checkbox_layout.addWidget(checkbox)
        checkbox_layout.setAlignment(Qt.AlignCenter)
        checkbox_layout.setContentsMargins(0, 0, 0, 0)
        checkbox_widget.setLayout(checkbox_layout)
        self.service_table.setCellWidget(row, 0, checkbox_widget)
        
        # 设置其他列
        name_item = QTableWidgetItem(service_name)
        name_item.setFlags(name_item.flags() | Qt.TextWordWrap)
        path_item = QTableWidgetItem(file_path)
        path_item.setFlags(path_item.flags() | Qt.TextWordWrap)
        
        self.service_table.setItem(row, 1, name_item)
        self.service_table.setItem(row, 2, path_item)
        self.service_table.setItem(row, 3, QTableWidgetItem(""))
        
        # 连接单元格编辑完成信号
        self.service_table.cellChanged.connect(self.on_service_name_changed)
        
        # 添加删除按钮
        btn = QPushButton("删除")
        btn.clicked.connect(lambda: self.del_service())
        btn_widget = QWidget()
        btn_layout = QHBoxLayout(btn_widget)
        btn_layout.addWidget(btn)
        btn_layout.setAlignment(Qt.AlignCenter)
        btn_layout.setContentsMargins(0, 0, 0, 0)
        btn_widget.setLayout(btn_layout)
        self.service_table.setCellWidget(row, 4, btn_widget)
        
        # 调整行高以适应多行内容
        self.service_table.resizeRowsToContents()
            
        self.append_log("服务管理", True, f"已添加服务: {service_name}，程序路径: {file_path}")
        self.save_config()
            
    def on_table_cell_clicked(self, row, column):
        """处理表格单元格点击事件"""
        # 选中整行
        self.service_table.selectRow(row)
        
        # 获取并切换复选框状态
        checkbox_widget = self.service_table.cellWidget(row, 0)
        if checkbox_widget:
            checkbox = checkbox_widget.findChild(QCheckBox)
            if checkbox:
                checkbox.setChecked(not checkbox.isChecked())
    
    def on_cell_changed(self, item):
        """处理单元格内容变化事件"""
        if item is None:
            return
            
        row = item.row()
        column = item.column()
        
        # 调整行高
        self.service_table.resizeRowToContents(row)
        
        # 如果是服务名称列的修改，保存配置
        if column == 1:
            self.save_config()
            
    def on_service_name_changed(self, row, column):
        """处理服务名称修改事件"""
        if column == 1:  # 只处理服务名称列的修改
            self.save_config()
            # 立即保存配置到文件
            self.service_table.item(row, column).setText(self.service_table.item(row, column).text())
        self.on_service_name_edit_finished(row, column)
            
    def on_service_name_edit_finished(self, row, column):
        """处理服务名称编辑完成事件"""
        if column == 1:  # 只处理服务名称列的修改
            self.save_config()
            
    def on_service_name_edit_lost_focus(self, row, column):
        """处理服务名称编辑框失去焦点事件"""
        if column == 1:  # 只处理服务名称列的修改
            self.save_config()
            
    def del_service(self):
        """删除服务"""
        # 获取发送信号的按钮
        button = self.sender()
        if isinstance(button, QPushButton) and button.text() == "删除":
            # 来自列表中的删除按钮
            current_row = self.service_table.indexAt(button.parent().pos()).row()
            if current_row >= 0:
                # 获取服务名称
                item = self.service_table.item(current_row, 1)
                if item:
                    service_name = item.text()
                    # 确认删除
                    reply = QMessageBox.question(self, '确认删除', 
                                               f'确定要删除服务 "{service_name}" 吗？',
                                               QMessageBox.Yes | QMessageBox.No, 
                                               QMessageBox.No)
                    if reply == QMessageBox.Yes:
                        self.service_table.removeRow(current_row)
                        self.append_log("服务管理", True, f"已删除服务: {service_name}")
                        self.save_config()
        else:
            # 来自底部的删除服务按钮
            checked_rows = []
            checked_services = []
            
            for row in range(self.service_table.rowCount()):
                checkbox_widget = self.service_table.cellWidget(row, 0)
                if checkbox_widget:
                    checkbox = checkbox_widget.findChild(QCheckBox)
                    if checkbox and checkbox.isChecked():
                        item = self.service_table.item(row, 1)
                        if item:
                            checked_rows.append(row)
                            checked_services.append(item.text())
            
            if not checked_rows:
                QMessageBox.warning(self, "警告", "请先勾选要删除的服务！")
                return
            
            # 确认删除
            services_str = "\n".join(checked_services)
            reply = QMessageBox.question(self, '确认删除', 
                                       f'确定要删除以下服务吗？\n{services_str}',
                                       QMessageBox.Yes | QMessageBox.No, 
                                       QMessageBox.No)
            
            if reply == QMessageBox.Yes:
                # 从后往前删除，避免索引变化
                for row in sorted(checked_rows, reverse=True):
                    self.service_table.removeRow(row)
                
                self.append_log("服务管理", True, f"已删除服务: {', '.join(checked_services)}")
                self.save_config()
        
    def initLogTab(self):
        """初始化操作日志Tab"""
        layout = QVBoxLayout()
        self.log_tab.setLayout(layout)
        
        # 操作日志区域
        self.log_widget = QTextEdit()
        self.log_widget.setReadOnly(True)
        layout.addWidget(self.log_widget)
        
        # 确保在__init__中调用initLogTab
        if hasattr(self, 'append_log'):
            self.append_log("系统初始化", True, "日志组件初始化完成")
        
    def setup_connections(self, db_conn, pw_gen, config_handler, service_mgr):
        """设置组件连接和保存组件引用"""
        # 保存组件引用
        self.db_conn = db_conn
        self.pw_gen = pw_gen
        self.config_handler = config_handler
        self.service_mgr = service_mgr
        
        # 连接UI信号与业务逻辑
        db_conn.password_changed_signal.connect(self.log_password_change)
        service_mgr.service_restarted_signal.connect(self.log_service_restart)
        config_handler.config_updated_signal.connect(self.log_config_update)
        
    def log_password_change(self, result, message):
        self.append_log("密码修改", result, message)
        
    def log_service_restart(self, service_name, result, message):
        self.append_log(f"服务重启: {service_name}", result, message)
        
    def log_config_update(self, config_path, result, message):
        self.append_log(f"配置更新: {config_path}", result, message)
        
    def append_log(self, action, result, message):
        timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        status = "成功" if result else "失败"
        log_entry = f"[{timestamp}] {action} - {status}: {message}"
        self.log_widget.append(log_entry)
        
    def eventFilter(self, obj, event):
        if obj is self.service_table.viewport() and event.type() == event.Leave:
            # 获取所有列的代理
            service_path_delegate = self.service_table.itemDelegateForColumn(2)
            config_path_delegate = self.service_table.itemDelegateForColumn(3)
            
            # 清除所有代理的悬停状态
            if isinstance(service_path_delegate, BrowseButtonDelegate):
                service_path_delegate.hover_index = None
            if isinstance(config_path_delegate, BrowseButtonDelegate):
                config_path_delegate.hover_index = None
            
            # 强制更新整个表格视图
            self.service_table.viewport().update()
            
        return super().eventFilter(obj, event)

    def trigger_password_change(self):
        """手动触发密码修改流程"""
        try:
            # 显示确认对话框
            reply = QMessageBox.question(self, '确认操作', 
                                       '确定要手动触发密码修改流程吗？\n这将会：\n1. 修改数据库密码\n2. 更新服务配置\n3. 重启相关服务',
                                       QMessageBox.Yes | QMessageBox.No, 
                                       QMessageBox.No)
            
            if reply == QMessageBox.Yes:
                self.append_log("密码修改", True, "开始手动触发密码修改流程...")
                
                # 1. 生成新密码
                new_password = self.pw_gen.generate()
                self.append_log("密码生成", True, "已生成新密码")
                # 打印new_password
                print('New password:', new_password)
                
                # 2. 修改数据库密码
                if self.db_conn.change_password(new_password):
                    self.append_log("数据库密码", True, "数据库密码修改成功")
                    
                    # 3. 更新配置文件
                    self.config_handler.update_password(new_password)
                    self.append_log("配置更新", True, "已更新所有配置文件中的密码")
                    
                    # 4. 重启选中的服务
                    for row in range(self.service_table.rowCount()):
                        checkbox_widget = self.service_table.cellWidget(row, 0)
                        if checkbox_widget:
                            checkbox = checkbox_widget.findChild(QCheckBox)
                            if checkbox and checkbox.isChecked():
                                service_name = self.service_table.item(row, 1).text()
                                service_path = self.service_table.item(row, 2).text()
                                if service_name and service_path:
                                    try:
                                        self.append_log("服务重启", True, f"开始重启服务: {service_name}")
                                        self.service_mgr.restart_service(service_name, service_path)
                                        self.append_log("服务重启", True, f"服务 {service_name} 重启完成")
                                    except Exception as e:
                                        error_msg = f"重启服务 {service_name} 失败: {str(e)}"
                                        self.append_log("服务重启", False, error_msg)
                                        # 显示错误消息但继续处理其他服务
                                        QMessageBox.warning(self, "服务重启警告", error_msg)
                                        continue
                    
                    self.append_log("密码修改", True, "密码修改流程已完成")
                    QMessageBox.information(self, "操作完成", "密码修改流程已完成")
                else:
                    raise Exception("数据库密码修改失败")
                    
        except Exception as e:
            self.append_log("密码修改", False, f"密码修改失败: {str(e)}")
            QMessageBox.critical(self, "错误", f"密码修改失败: {str(e)}")

    def save_config(self):
        """保存密码修改配置"""
        try:
            # 获取数据库连接设置
            database = {
                'ip': self.db_ip.text(),
                'port': int(self.db_port.text()) if self.db_port.text() else None,
                'username': self.db_user.text(),
                'password': self.db_pwd.text(),
                'database': self.db_name.text()
            }
            
            # 获取频率设置
            freq_min = int(self.freq_min.text())
            freq_max = int(self.freq_max.text())
            
            # 获取复杂度设置
            complexity = {
                'length': self.length_check.isChecked(),
                'upper': self.upper_check.isChecked(),
                'lower': self.lower_check.isChecked(),
                'number': self.number_check.isChecked(),
                'special': self.special_check.isChecked()
            }
            
            # 保存服务列表配置
            services = []
            for row in range(self.service_table.rowCount()):
                service = {
                    'name': self.service_table.item(row, 1).text(),
                    'path': self.service_table.item(row, 2).text(),
                    'config_path': self.service_table.item(row, 3).text() if self.service_table.item(row, 3) else '',
                    'config_content': self.service_table.item(row, 4).text() if self.service_table.item(row, 4) else ''
                }
                services.append(service)
            
            # 保存到JSON配置文件
            config = {
                'database': database,
                'frequency': {'min': freq_min, 'max': freq_max},
                'complexity': complexity,
                'services': services
            }
            
            with open('./config/config.json', 'w', encoding='utf-8') as f:
                json.dump(config, f, ensure_ascii=False, indent=4)
                
            self.append_log("配置保存", True, "密码修改配置已保存到config.json")
            
        except ValueError:
            self.append_log("配置保存", False, "频率设置必须为整数")
        except Exception as e:
            self.append_log("配置保存", False, f"保存配置失败: {str(e)}")